#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""mysqlpass项目打包脚本
用于将mysqlpass项目打包成一个可独立下载安装的文件
"""

import os
import sys
import subprocess
import shutil
import argparse
import platform
from datetime import datetime

# 确保脚本在正确的目录下运行
script_dir = os.path.dirname(os.path.abspath(__file__))
os.chdir(script_dir)

# 定义项目相关路径
PROJECT_NAME = "mysqlpass"
MAIN_SCRIPT = "main.py"
OUTPUT_DIR = os.path.join("..", "build_output")
REQUIREMENTS_FILE = "requirements.txt"

# 定义打包参数
BUILD_NAME = "MySQLPass"
BUILD_VERSION = "1.0.0"


def check_pyinstaller():
    """检查PyInstaller是否已安装"""
    try:
        subprocess.run([sys.executable, "-m", "PyInstaller", "--version"], 
                       check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        return True
    except (subprocess.CalledProcessError, FileNotFoundError):
        return False


def install_pyinstaller():
    """安装PyInstaller"""
    print("正在安装PyInstaller...")
    try:
        subprocess.run([sys.executable, "-m", "pip", "install", "pyinstaller"], 
                      check=True)
        print("PyInstaller安装成功")
        return True
    except subprocess.CalledProcessError:
        print("PyInstaller安装失败")
        return False


def clean_build_dir():
    """清理之前的构建目录"""
    print("清理之前的构建文件...")
    # 清理PyInstaller生成的目录
    for dir_name in ["build", "dist"]:
        dir_path = os.path.join(script_dir, dir_name)
        if os.path.exists(dir_path):
            shutil.rmtree(dir_path)
    
    # 清理spec文件
    for file in os.listdir(script_dir):
        if file.endswith(".spec"):
            os.remove(os.path.join(script_dir, file))
    
    # 清理输出目录
    if os.path.exists(OUTPUT_DIR):
        shutil.rmtree(OUTPUT_DIR)


def create_output_dir():
    """创建输出目录"""
    os.makedirs(OUTPUT_DIR, exist_ok=True)


def build_with_pyinstaller(onefile=True, include_updates=True):
    """使用PyInstaller打包应用"""
    print(f"开始打包{PROJECT_NAME}项目...")
    
    # 构建PyInstaller命令参数
    cmd = [
        sys.executable,
        "-m",
        "PyInstaller",
        "--name", BUILD_NAME,
        "--windowed",  # 不显示控制台窗口
        "--icon", os.path.join("src", "data", "mp.png"),  # 使用mp.png作为图标
    ]
    
    # 添加版本信息
    cmd.extend([
        "--version-file", "version_info.txt"
    ])
    
    # 添加依赖文件
    cmd.extend([
        "--add-data", f"src{os.pathsep}src",
        "--add-data", f"README.md{os.pathsep}.",
        "--add-data", f"README.en.md{os.pathsep}."
    ])
    
    # 如果需要包含updates目录
    if include_updates and os.path.exists("updates"):
        cmd.extend(["--add-data", f"updates{os.pathsep}updates"])
    
    # 设置单文件或文件夹模式
    if onefile:
        cmd.append("--onefile")
    
    # 添加主脚本
    cmd.append(MAIN_SCRIPT)
    
    # 执行打包命令
    try:
        subprocess.run(cmd, check=True)
        print("打包成功")
        return True
    except subprocess.CalledProcessError as e:
        print(f"打包失败: {e}")
        return False


def create_version_info_file():
    """创建版本信息文件"""
    # 使用最直接的方式构建版本信息文件内容
    version_info_content = """
VSVersionInfo(
{
  'ffi': {'ffiwValue': 16777216},
  'mask': 0x3f,
  'os': 0x40004,
  'filevers': (1, 0, 0, 0),
  'prodvers': (1, 0, 0, 0),
  'pszOSVerName': 'Windows NT',
  'pszFileDesc': 'MySQLPass - 自由使用的MySQL工具',
  'pszInternalName': 'MySQLPass',
  'pszOriginalFilename': 'MySQLPass.exe',
  'pszProductName': 'MySQLPass',
  'pszCompanyName': 'MySQLPass Team',
  'pszLegalCopyright': '© 2025 MySQLPass. All rights reserved.',
  'pszLegalTrademarks': '',
  'pszComments': '安全、便捷的MySQL密码管理解决方案'
}
)
"""
    
    with open("version_info.txt", "w", encoding="utf-8") as f:
        f.write(version_info_content)
    
    return "version_info.txt"


def copy_output_files(onefile=True):
    """复制打包后的文件到输出目录"""
    print("复制打包后的文件到输出目录...")
    
    # 复制主程序文件
    if onefile:
        exe_path = os.path.join("dist", f"{BUILD_NAME}.exe")
        if os.path.exists(exe_path):
            shutil.copy(exe_path, OUTPUT_DIR)
            print(f"已复制主程序文件: {BUILD_NAME}.exe")
    else:
        dist_dir = os.path.join("dist", BUILD_NAME)
        if os.path.exists(dist_dir):
            shutil.copytree(dist_dir, os.path.join(OUTPUT_DIR, BUILD_NAME))
            print(f"已复制应用目录: {BUILD_NAME}")
    
    # 复制其他必要文件
    for file_name in ["README.md", "README.en.md"]:
        file_path = os.path.join(script_dir, file_name)
        if os.path.exists(file_path):
            shutil.copy(file_path, OUTPUT_DIR)
    
    # 复制requirements.txt文件（用于参考）
    if os.path.exists(REQUIREMENTS_FILE):
        shutil.copy(REQUIREMENTS_FILE, OUTPUT_DIR)
    
    return True


def create_zip_package():
    """创建ZIP压缩包"""
    print("创建ZIP压缩包...")
    
    # 定义ZIP文件名
    zip_file_name = f"{BUILD_NAME}-{BUILD_VERSION}-{platform.system()}-{platform.architecture()[0]}"
    if platform.system() == "Windows":
        zip_file_name += ".zip"
    else:
        zip_file_name += ".tar.gz"
    
    zip_file_path = os.path.join(script_dir, zip_file_name)
    
    # 创建压缩包
    if platform.system() == "Windows":
        # 在Windows上使用shutil.make_archive
        shutil.make_archive(
            base_name=os.path.join(script_dir, zip_file_name.replace(".zip", "")),
            format="zip",
            root_dir=OUTPUT_DIR
        )
    else:
        # 在其他平台上使用tarfile
        import tarfile
        with tarfile.open(zip_file_path, "w:gz") as tar:
            tar.add(OUTPUT_DIR, arcname=os.path.basename(OUTPUT_DIR))
    
    print(f"已创建压缩包: {zip_file_name}")
    return zip_file_path


def create_installer_script():
    """创建Windows安装脚本"""
    if platform.system() != "Windows":
        return None
    
    print("创建Windows安装脚本...")
    
    installer_script = f'''
@echo off

rem MySQLPass 安装脚本
setlocal enabledelayedexpansion

rem 设置UTF-8编码
chcp 65001

rem 获取当前日期时间
for /f "tokens=2 delims==" %%a in ('wmic OS Get localdatetime /value') do set "datetime=%%a"
set "year=!datetime:~0,4!"
set "month=!datetime:~4,2!"
set "day=!datetime:~6,2!"
set "install_date=!year!-!month!-!day!"

rem 定义安装路径
set "default_install_dir=%ProgramFiles%\{BUILD_NAME}"
set "install_dir=%default_install_dir%"

:prompt_install_dir
set /p "user_input=请输入安装路径 [默认: %default_install_dir%]: "
if not "%user_input%"=="" set "install_dir=%user_input%"

rem 检查路径是否有效
if not exist "%install_dir%" mkdir "%install_dir%"
if not exist "%install_dir%" (
    echo 无法创建安装目录，请选择其他路径
    goto prompt_install_dir
)

rem 复制文件到安装目录
xcopy /s /e /i /y "{OUTPUT_DIR}\*" "%install_dir%"

rem 创建桌面快捷方式
set "shortcut_name={BUILD_NAME}.lnk"
set "target_path=%install_dir%\{BUILD_NAME}.exe"
set "icon_path=%install_dir%\src\data\icon.ico"

rem 使用PowerShell创建快捷方式
powershell -Command "$WshShell = New-Object -ComObject WScript.Shell; $Shortcut = $WshShell.CreateShortcut([System.Environment]::GetFolderPath('Desktop')+'\%shortcut_name%'); $Shortcut.TargetPath = '%target_path%'; $Shortcut.WorkingDirectory = '%install_dir%'; $Shortcut.IconLocation = '%icon_path%'; $Shortcut.Save()"

rem 创建开始菜单快捷方式
set "start_menu_dir=%APPDATA%\Microsoft\Windows\Start Menu\Programs\{BUILD_NAME}"
if not exist "%start_menu_dir%" mkdir "%start_menu_dir%"
powershell -Command "$WshShell = New-Object -ComObject WScript.Shell; $Shortcut = $WshShell.CreateShortcut('%start_menu_dir%\%shortcut_name%'); $Shortcut.TargetPath = '%target_path%'; $Shortcut.WorkingDirectory = '%install_dir%'; $Shortcut.IconLocation = '%icon_path%'; $Shortcut.Save()"

rem 显示安装完成信息
cls
echo ==================================================
echo {BUILD_NAME} v{BUILD_VERSION}
echo 安装成功!
echo 安装路径: %install_dir%
echo 安装日期: %install_date%
echo ==================================================
echo 您可以通过桌面快捷方式或开始菜单启动程序
echo 感谢使用{BUILD_NAME}!
echo ==================================================
pause
'''
    
    installer_path = os.path.join(OUTPUT_DIR, "install_mysqlpass.bat")
    with open(installer_path, "w", encoding="utf-8") as f:
        f.write(installer_script)
    
    print(f"已创建安装脚本: {installer_path}")
    return installer_path


def main():
    """主函数"""
    parser = argparse.ArgumentParser(description='mysqlpass项目打包脚本')
    parser.add_argument('--no-onefile', action='store_true', help='不使用单文件模式打包')
    parser.add_argument('--no-updates', action='store_true', help='不包含updates目录')
    parser.add_argument('--no-zip', action='store_true', help='不创建ZIP压缩包')
    parser.add_argument('--no-installer', action='store_true', help='不创建安装脚本')
    
    args = parser.parse_args()
    onefile = not args.no_onefile
    include_updates = not args.no_updates
    create_zip = not args.no_zip
    create_install = not args.no_installer
    
    # 1. 检查并安装PyInstaller
    if not check_pyinstaller():
        if not install_pyinstaller():
            print("无法安装PyInstaller，退出打包")
            sys.exit(1)
    
    try:
        # 2. 清理之前的构建文件
        clean_build_dir()
        
        # 3. 创建版本信息文件
        create_version_info_file()
        
        # 4. 创建输出目录
        create_output_dir()
        
        # 5. 使用PyInstaller打包应用
        if not build_with_pyinstaller(onefile, include_updates):
            print("打包失败，退出")
            sys.exit(1)
        
        # 6. 复制输出文件到指定目录
        copy_output_files(onefile)
        
        # 7. 创建安装脚本（Windows系统）
        if platform.system() == "Windows" and create_install:
            create_installer_script()
        
        # 8. 创建ZIP压缩包
        if create_zip:
            zip_path = create_zip_package()
            print(f"\n打包完成! 可分发文件位于: {zip_path}")
        else:
            print(f"\n打包完成! 可分发文件位于: {OUTPUT_DIR}")
            
        # 9. 显示完成信息
        print("\nMySQLPass 打包任务已成功完成!")
        print(f"版本: {BUILD_VERSION}")
        print(f"打包时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
        print(f"打包选项:")
        print(f"  - 单文件模式: {'是' if onefile else '否'}")
        print(f"  - 包含updates目录: {'是' if include_updates else '否'}")
        print(f"  - 创建ZIP压缩包: {'是' if create_zip else '否'}")
        print(f"  - 创建安装脚本: {'是' if (platform.system() == 'Windows' and create_install) else '否'}")
        
    except Exception as e:
        print(f"打包过程中发生错误: {e}")
        import traceback
        traceback.print_exc()
        sys.exit(1)
    
    finally:
        # 清理临时文件
        if os.path.exists("version_info.txt"):
            os.remove("version_info.txt")


if __name__ == "__main__":
    main()